package com.aries.remoteplus.view;

import java.io.IOException;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import com.aries.remoteplus.R;
import com.aries.remoteplus.core.CommonFuncs;
import com.aries.remoteplus.core.RPConstants;
import com.illposed.osc.OSCMessage;
import com.illposed.osc.OSCPortOut;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.StrictMode;
import android.os.Vibrator;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnKeyListener;
import android.view.View.OnTouchListener;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;

public class BasicInputActivity extends Activity {

	private OSCPortOut basicOscPortOut;
	private TextView mousePad;
	private InputMethodManager inputMethodManager;
	private EditText advanceEditText;
	private String defaultText;
	
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		this.setContentView(R.layout.basic_input);
		
		this.mousePad = (TextView) this.findViewById(R.id.mousePad);
		this.mousePad.setOnTouchListener(new MousePadTouchListener());
		
		Intent dataIntent = this.getIntent();                   
		this.basicOscPortOut = CommonFuncs.getPortOutByIntent(dataIntent);
		
		this.initAdvancedText();
	}
	
	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event)
	{
		if (keyCode == KeyEvent.KEYCODE_MENU)
		{
			this.inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
			this.inputMethodManager.toggleSoftInputFromWindow(this.mousePad.getWindowToken(), InputMethodManager.SHOW_IMPLICIT
														, InputMethodManager.HIDE_IMPLICIT_ONLY);
			
		}
		else if (keyCode == KeyEvent.KEYCODE_BACK) 
		{
			this.finish();
		}
		
		return true;
	}
	
	private void initAdvancedText() 
	{
		this.advanceEditText = (EditText) this.findViewById(R.id.advanceEditText);;
		
		this.advanceEditText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);//make sure keyboard doesnt go fullscreen in landscape mode

		this.defaultText = "a ";
		advanceEditText.setText(this.defaultText);
		
		// listener
		advanceEditText.setOnKeyListener(new OnKeyListener(){

				@Override
				public boolean onKey(View v, int keyCode, KeyEvent event)
				{
					defaultText = "a ";
					advanceEditText.setText(defaultText);
					
					if ((keyCode==KeyEvent.KEYCODE_DEL||keyCode==KeyEvent.KEYCODE_ENTER)
							&& event.getAction()==KeyEvent.ACTION_UP)
					{
						sendSoftKey(keyCode);
					}
					
					return false;
				}
		});
		
		advanceEditText.addTextChangedListener(new TextWatcher() {
			
			@Override
			public void onTextChanged(CharSequence s, int start, int before,
					int count)
			{
					if (s.toString().equals(defaultText))
					{
						advanceEditText.requestFocus();
						advanceEditText.setSelection(2);
						
						return ;
					}
					String change = s.toString().substring(start, start + count);
					
					sendText(change);

					defaultText = "a ";
					advanceEditText.setText(defaultText);
			}

			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after)
			{
				// TODO Auto-generated method stub
				
			}

			@Override
			public void afterTextChanged(Editable s)
			{
				// TODO Auto-generated method stub
				
			}
		});
	}
	
	private void sendMouseMoveInfo(int type, float x, float y)
	{
		Object args[] = new Object[3];
		args[0] = type;
		args[1] = x;
		args[2] = y;
		
		OSCMessage message = new OSCMessage("/mouseMove", args);
		
		this.basicPortOut(message);
	}
	
	private void sendButtonClickInfo(int type, boolean isDrag)
	{
		Object[] args = new Object[1];
		args[0] = isDrag;
		String address = type == RPConstants.LEFT_BUTTON_CLICK ? "/leftButton" : "/rightButton";
		OSCMessage message = new OSCMessage(address, args);
		
		this.basicPortOut(message);
	}
	
	private void sendScrollInfo(int type, float y)
	{
		Object[] args = new Object[2];
		args[0] = type;
		args[1] = y>0 ? 1 : -1;
		
		OSCMessage message = new OSCMessage("/wheelScroll", args);
		
		this.basicPortOut(message);
	}
	
	private void sendText(String text)
	{
		Object[] args = new Object[] {text};
		OSCMessage message = new OSCMessage("/textInput", args);
		
		this.basicPortOut(message);	
	}
	
	private void sendSoftKey(int keyCode)
	{
		Object[] args = new Object[]{keyCode==KeyEvent.KEYCODE_DEL ? "DELETE" : "ENTER"};
		OSCMessage message = new OSCMessage("/softKey", args);
		
		this.basicPortOut(message);
	}
	
	private boolean basicPortOut(OSCMessage message)
	{
		try
		{
			if (basicOscPortOut != null)
			{
				basicOscPortOut.send(message);
			}
			
			return true;
		} catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return false;
	}
	
 	class MousePadTouchListener implements OnTouchListener
	{
		private float xHistory;
		private float yHistory;
		private int lastPointerCount;
		private int motionType;
		private long lastTabTime;
		private long press2DragTime;
		private long timeGap;
		private Vibrator vibrator;
		private Timer pressTimer;
		private boolean isRightButton = false;
		private int scrollCounter;
		
		@Override
		public boolean onTouch(View v, MotionEvent event)
		{
			// TODO Auto-generated method stub			
			float xMoveDis = 0f;
			float yMoveDis = 0f;
			int pointerCount = event.getPointerCount();
			
			switch ( event.getAction() & MotionEvent.ACTION_MASK)
			{
				case MotionEvent.ACTION_DOWN:
				{
					lastPointerCount = pointerCount;
					lastTabTime = System.currentTimeMillis();
					
					press2DragTime = System.currentTimeMillis();
					pressTimer = new Timer();
					TimerTask pressTimerTask = new TimerTask() {
						
						@Override
						public void run()
						{
							// TODO Auto-generated method stub
							timeGap = System.currentTimeMillis() - press2DragTime;
							if (timeGap >= RPConstants.DRAG_TIME_GAP)
							{
								vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
								vibrator.vibrate(100);
								
								motionType = RPConstants.MOTION_DRAG;
								sendButtonClickInfo(RPConstants.LEFT_BUTTON_CLICK, true);
								
								pressTimer.cancel();
							}
						}
					};
					Date currentDate = new Date(System.currentTimeMillis());
					pressTimer.schedule(pressTimerTask, currentDate, 200);
					
					xMoveDis = 0;
					yMoveDis = 0;
					
					xHistory = event.getX();
					yHistory = event.getY();
					
					break;
				}
					
				case MotionEvent.ACTION_UP:
				{	
					if (motionType != RPConstants.MOTION_DRAG)
					{
						pressTimer.cancel();
						long rclickTimeGap = System.currentTimeMillis() - lastTabTime;
						
						if (lastPointerCount==1 && rclickTimeGap<=RPConstants.CLICK_TIME_GAP)
						{
							sendButtonClickInfo(RPConstants.LEFT_BUTTON_CLICK, false);
							motionType = RPConstants.LEFT_BUTTON_CLICK;
						}
					}
					
					xMoveDis = 0;
					yMoveDis = 0;
					
					break;
				}
				
				case MotionEvent.ACTION_MOVE:
				{	
					xMoveDis = event.getX() - xHistory;
					yMoveDis = event.getY() - yHistory;
					
					double moveDis = Math.sqrt(Math.pow(xMoveDis, 2.0) + Math.pow(yMoveDis, 2.0));
					
					if (moveDis > RPConstants.IGNORE_MOVE_RANGE)
					{
						if (motionType != RPConstants.MOTION_DRAG)
						{
							pressTimer.cancel();
						}
						if (lastPointerCount == 1)
						{
							xHistory = event.getX();
							yHistory = event.getY();	
							
							motionType = RPConstants.MOTION_MOVE;
							sendMouseMoveInfo(motionType, xMoveDis, yMoveDis);
						}
						else if (pointerCount == 2)
						{
							if (scrollCounter >= RPConstants.IGNORE_SCROLL_COUNT)
							{
								int point0 = event.getPointerId(0);
								int point1 = event.getPointerId(1);
								
								float yPos = ( event.getY(point0)+event.getY(point1) )/2;
								
								yMoveDis = yPos-yHistory;
								
								sendScrollInfo(motionType, yMoveDis);
								motionType = RPConstants.MOTION_SCROLL;
								yHistory = yPos;
								scrollCounter = 0;
							}
							else
							{
								scrollCounter++;
							}
						}
					}
					
					break;
				}
				
				case MotionEvent.ACTION_POINTER_DOWN:
				{
					if (timeGap<=RPConstants.RIGHT_BUTTON_TIME_GAP && pointerCount==2)
					{
						pressTimer.cancel();
						
						isRightButton = true;
					}
					
					break;
				}
				
				case MotionEvent.ACTION_POINTER_UP:
				{
					if (isRightButton && motionType!=RPConstants.MOTION_SCROLL)
					{
						sendButtonClickInfo(RPConstants.RIGHT_BUTTON_CLICK, false);
						motionType = RPConstants.RIGHT_BUTTON_CLICK;
						isRightButton = false;
					}
					
					break;
				}
					
				default:
					break;
			}
			
			lastPointerCount = pointerCount;
			return true;
		}
		
	}
} 

